/**
 * 在全局变量下扩展一个sr插件库的对象,在浏览器中全局变量是window
 * 
 * PS1:如果把本文件中的模块单独拆开的话，可以这样判断sr命名空间是否已经被初始化，如果未初始化，则初始化。
 * sr = (typeof (sr) == "undefined" ? {} : sr);
 * 
 * PS2:入参推荐这样写：(function(){ return this || (0, eval)('this'); }()) || {}
 * 可实现的在任何宿主环境中运行，而不仅仅是浏览器中。如果只需要支持浏览器，可以直接传入window || {}
 * 
 * PS3:第一行的分号是为了对其他js文件的兼容处理，使得本文件不会受其他文件的影响。
 */
;
(function(global, undefined) {
	/**
	 * 在全局变量下扩展的自定义对象，所有的自定义插件都放在该对象下
	 */
	var sr = (function() {
		/**
		 * 加密模块
		 */
		var crypto = (function() {
			/**
			 * aes加密子模块
			 * 使用本模块需要引入
			 * <script src="../../../../share/jeffMott/cryptoJS/main/components/core.js"></script>
			 * <script src="../../../../share/jeffMott/cryptoJS/main/components/enc-base64.js"></script>
			 * <script src="../../../../share/jeffMott/cryptoJS/main/components/cipher-core.js"></script>
			 * <script src="../../../../share/jeffMott/cryptoJS/main/components/aes.js"></script>
			 * <script src="../../../../share/jeffMott/cryptoJS/main/components/pad-zeropadding.js"></script>
			 */
			var aes = (function() {
				/**
				 * aes加密
				 * @param {Object} data 明文
				 * @param {Object} key 密钥
				 * @param {Object} iv 偏移量
				 * @param {Object} length 加密强度
				 */
				var encrypt = function(data, key, iv, length) {
					/*
					 * 处理入参
					 */
					// 将密码key解析为类byte[]对象(这是一种CryptoJS定义的对象)
					var keyBytesObj = CryptoJS.enc.Utf8.parse(key);
					// 将初始化向量iv解析为类byte[]对象(这是一种CryptoJS定义的对象)
					var ivBytesObj = CryptoJS.enc.Utf8.parse(iv);

					/*
					 * AES加密
					 * CBC模式
					 * ZeroPadding填充
					 */
					var encrypted = CryptoJS.AES.encrypt(data, keyBytesObj, {
						iv: ivBytesObj,
						mode: CryptoJS.mode.CBC,
						padding: CryptoJS.pad.ZeroPadding
					});
					// 取出加密结果(返回的是十六进制字符串)
					var encryptedData2Hex = encrypted.ciphertext.toString();
					return encryptedData2Hex;
				};

				/**
				 * 将十六进制字符串转换为base64编码
				 * @param {Object} encryptedData2Hex 十六进制字符串
				 */
				var hex2Base64 = function(encryptedData2Hex) {
					// 将十六进制格式的密文转换为类byte[]对象(这是一种CryptoJS定义的对象)
					var encryptedDataBytesObj = CryptoJS.enc.Hex.parse(encryptedData2Hex);
					// 将类byte[]对象转换为base64格式的字符串
					var encryptedData2Base64 = CryptoJS.enc.Base64.stringify(encryptedDataBytesObj);
					return encryptedData2Base64;
				};

				/**
				 * AES解密，有两种写法
				 * 1、从加密结果对象解密（暂不支持）
				 * 2、从base64字符串解密
				 * @param {Object} encryptedData2Base64 base64格式的密文
				 * @param {Object} key 密钥
				 * @param {Object} iv 偏移量
				 * @param {Object} length 加密强度
				 */
				var decrypt = function(encryptedData2Base64, key, iv, length) {
					/*
					 * 处理入参
					 */
					// 将密码key解析为类byte[]对象(这是一种CryptoJS定义的对象)
					var keyBytesObj = CryptoJS.enc.Utf8.parse(key);
					// 将初始化向量iv解析为类byte[]对象(这是一种CryptoJS定义的对象)
					var ivBytesObj = CryptoJS.enc.Utf8.parse(iv);

					//					var decrypted = CryptoJS.AES.decrypt(encrypted, keyBytesObj, {
					//						iv: ivBytesObj,
					//						mode: CryptoJS.mode.CBC,
					//						padding: CryptoJS.pad.ZeroPadding
					//					});
					var decrypted = CryptoJS.AES.decrypt(encryptedData2Base64, keyBytesObj, {
						iv: ivBytesObj,
						mode: CryptoJS.mode.CBC,
						padding: CryptoJS.pad.ZeroPadding
					});
					// 取出解密结果
					var decryptedData = decrypted.toString(CryptoJS.enc.Utf8);
					return decryptedData;
				};

				/**
				 * 示例
				 */
				var demo = function() {
					// 明文
					var data = "张三是猪头111Test";
					// 密钥
					var key = "1234567812345678";
					// 初始化向量（AES加密的某些模式支持初始化向量）
					var iv = "1234567812345678";

					var encryptedData2Hex = encrypt(data, key, iv);
					console.log(encryptedData2Hex);
					var encryptedData2Base64 = hex2Base64(encryptedData2Hex);
					console.log(encryptedData2Base64);
					var decryptedData = decrypt(encryptedData2Base64, key, iv);
					console.log(decryptedData);
				}

				return {
					"encrypt": encrypt,
					"hex2Base64": hex2Base64,
					"decrypt": decrypt,
					"demo": demo
				};

			})();
			return {
				"aes": aes
			};
		})();

		return {
			"crypto": crypto
		};
	})();

	// 最后将插件对象暴露给全局对象
	!('sr' in global) && (global.sr = sr);

})((function() {
	return this || (0, eval)('this');
}()) || {});